# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import logging

logging.basicConfig(level=logging.INFO)

SP = ' '  # space, used to strip the annoying space of the data parsed by xml.etree.ElementTree


def parse_xml(xml_str, is_received=True):
    """Parse the Wexin xml data and return a Msg sub object"""
    xml_data = ET.fromstring(xml_str)

    # if the xml is received form User
    if is_received:
        UserName_host = xml_data.find('ToUserName').text
        UserName_client = xml_data.find('FromUserName').text

    # or the xml is to send to the User
    else:
        # It seems no need to specify the difference when parsing
        # because it is always received.
        UserName_host = xml_data.find('FromUserName').text
        UserName_client = xml_data.find('ToUserName').text

    if xml_data.find('MsgType').text.strip(' ') == 'text':
        return TextMessage(xml_data, UserName_host=UserName_host, UserName_client=UserName_client)


def strip_spaces(func):
    """To strip the spaces that start at the lines in the xml_template,
     hence the xml after rendering will be tidy to read when printing.It targets
      at the render method of MsgBaseClass Class"""
    def wrapper(*arg, **kw):
        temp_str = func(*arg, **kw).split('\n')
        temp_str = [x.strip(' ') for x in temp_str]
        temp_str = [x for x in temp_str if x]  # filter out the empty str
        temp_str = '\n'.join(temp_str)

        return temp_str
    return wrapper


class MsgBaseClass(object):
    def __init__(self, xml_data, UserName_host, UserName_client):
        """Define some basic variables for Weixin message's XML data"""
        self.UserName_host = UserName_host.strip(SP)
        self.UserName_client = UserName_client.strip(SP)
        self.data = dict()
        self.data['CreateTime'] = xml_data.find('CreateTime').text.strip(SP)
        self.data['MsgType'] = xml_data.find('MsgType').text.strip(SP)

        # self.xml_template  # it should be better to use the xml module to assemble
        # Currently, we use str.format as a template engine.
        # Possibly such format is fairly not recommended.
        self._xml_template = """
            <xml>
            <ToUserName> <![CDATA[{ToUserName}]]> </ToUserName>
            <FromUserName> <![CDATA[{FromUserName}]]> </FromUserName>
            <CreateTime> <![CDATA[{CreateTime}]]> </CreateTime>
            <MsgType> <![CDATA[{MsgType}]]> </MsgType>
            {other_xml_text}
            </xml>
            """

    @strip_spaces
    def render(self, is_send=True, other_xml_text=""):
        """Render the xml text send to Weixin API."""
        # if the xml is to send to User
        if is_send:
            ToUserName = self.UserName_client
            FromUserName = self.UserName_host
        else:
            ToUserName = self.UserName_host
            FromUserName = self.UserName_client

        self._xml_template = self._xml_template.format(
            ToUserName=ToUserName,
            FromUserName=FromUserName,
            other_xml_text=other_xml_text,
            **self.data
        )

        # logging.info('@message render type:%s:%s \n' % (self._xml_template, type(self._xml_template)))
        return self._xml_template


class TextMessage(MsgBaseClass):
    def __init__(self, xml_data, UserName_host, UserName_client):
        super(TextMessage, self).__init__(xml_data, UserName_host, UserName_client)
        self.data['Content'] = xml_data.find('Content').text.strip(SP)

        other_xml_text = """
        <Content><![CDATA[{Content}]]> </Content>
        """
        self._xml_template = self._xml_template.format(other_xml_text=other_xml_text,
            ToUserName='{ToUserName}',
            FromUserName='{FromUserName}',
            **dict([(k, '{%s}' % k) for k in self.data.keys()]))


class ImageMessage(MsgBaseClass):
    def __init__(self, xml_data, UserName_host, UserName_client):
        super(ImageMessage, self).__init__(xml_data, UserName_host, UserName_client)


if __name__ == '__main__':
    string = """
    <xml>
    <ToUserName> <![CDATA[{ToUserName}]]> </ToUserName>
    <FromUserName> <![CDATA[{FromUserName}]]> </FromUserName>
    <CreateTime><![CDATA[CreateTime]]> </CreateTime>
    <MsgType> <![CDATA[text]]> </MsgType>
    <Content><![CDATA[text message]]> </Content>
    {other_xml_text}
    </xml>
    """
    i = TextMessage(ET.fromstring(string), 'host', 'client')
    t = parse_xml(string)
    print(t.render())





